#include <cppunit/config/SourcePrefix.h>

#include "RelationshipClauseTable.h"
#include "TestRelationshipClauseTable.h"

void RelationshipClauseTableTest::setUp() {
	std::cout << "Test RelationshipClauseTable setUp()\n";
}

void RelationshipClauseTableTest::tearDown() {
}

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( RelationshipClauseTableTest );

// method to test the constructor
void RelationshipClauseTableTest::testConstructor() {
	// Just to ensure it does not produce errors
	RelationshipClauseTable relClauseTable;
}

// Tests the addRelationshipEntry function
void RelationshipClauseTableTest::testAddRelationshipEntry() {
	RelationshipClauseTable relClauseTable;

	CPPUNIT_ASSERT(true == relClauseTable.addRelationshipEntry(AFFECTS, 
																"a", SYNONYM_ASSIGN, 
																"1", INTEGER));

	// Empty string arguments return false
	CPPUNIT_ASSERT(false == relClauseTable.addRelationshipEntry(AFFECTS, 
																"", SYNONYM_ASSIGN,
																"1", INTEGER));
	CPPUNIT_ASSERT(false == relClauseTable.addRelationshipEntry(AFFECTS, 
																"a", SYNONYM_ASSIGN,
																"", INTEGER));

	// same entry will not be added twice
	CPPUNIT_ASSERT(false == relClauseTable.addRelationshipEntry(AFFECTS, 
															"a", SYNONYM_ASSIGN, 
															"1", INTEGER));

}

// Tests the getRelationshipEntry function
void RelationshipClauseTableTest::testGetRelationshipEntry() {
	RelationshipClauseTable relClauseTable;

	// Add a few entries
	relClauseTable.addRelationshipEntry(FOLLOWS,
										"a", SYNONYM_ASSIGN,
										"5", INTEGER);
	relClauseTable.addRelationshipEntry(PARENT,
										"s", SYNONYM_STMT,
										"5", INTEGER);

	// Try to get them
	RelationshipEntry relEntry;
	// First
	relEntry = relClauseTable.getRelationshipEntry(0);
	CPPUNIT_ASSERT(FOLLOWS == relEntry.relationshipType);
	CPPUNIT_ASSERT(2 == relEntry.numberOfArguments);
	CPPUNIT_ASSERT("a" == relEntry.relationshipArguments[0]);
	CPPUNIT_ASSERT(SYNONYM_ASSIGN == relEntry.relationshipArgumentTypes[0]);
	CPPUNIT_ASSERT("5" == relEntry.relationshipArguments[1]);
	CPPUNIT_ASSERT(INTEGER == relEntry.relationshipArgumentTypes[1]);
	// Second
	relEntry = relClauseTable.getRelationshipEntry(1);
	CPPUNIT_ASSERT(PARENT == relEntry.relationshipType);
	CPPUNIT_ASSERT(2 == relEntry.numberOfArguments);
	CPPUNIT_ASSERT("s" == relEntry.relationshipArguments[0]);
	CPPUNIT_ASSERT(SYNONYM_STMT == relEntry.relationshipArgumentTypes[0]);
	CPPUNIT_ASSERT("5" == relEntry.relationshipArguments[1]);
	CPPUNIT_ASSERT(INTEGER == relEntry.relationshipArgumentTypes[1]);
	// Out of bounds
	relEntry = relClauseTable.getRelationshipEntry(2); 
}

// Tests the getNumberOfEntries function
void RelationshipClauseTableTest::testGetNumberOfEntries() {
	RelationshipClauseTable relClauseTable;

	// Add some entries
	relClauseTable.addRelationshipEntry(FOLLOWS, 
										"a", SYNONYM_ASSIGN, 
										"5", INTEGER);
	relClauseTable.addRelationshipEntry(PARENT, 
										"s", SYNONYM_ASSIGN, 
										"5", INTEGER);
	relClauseTable.addRelationshipEntry(PARENT, 
									"s", SYNONYM_ASSIGN, 
									"5", INTEGER);
	relClauseTable.addRelationshipEntry(PARENT, 
									"s", SYNONYM_ASSIGN, 
									"s", SYNONYM_ASSIGN);
	relClauseTable.addRelationshipEntry(PARENT, 
									"s", SYNONYM_ASSIGN, 
									"s", SYNONYM_STMT);
	relClauseTable.addRelationshipEntry(PARENT_STAR, 
									"s", SYNONYM_ASSIGN, 
									"s", SYNONYM_STMT);

	// Test the number of entries
	CPPUNIT_ASSERT(5 == relClauseTable.getNumberOfEntries());
}


void RelationshipClauseTableTest::testExistsRelationshipEntry() {
	RelationshipClauseTable relClauseTable;

	relClauseTable.addRelationshipEntry(FOLLOWS, 
										"a", SYNONYM_ASSIGN, 
										"5", INTEGER);
	relClauseTable.addRelationshipEntry(PARENT, 
										"s", SYNONYM_ASSIGN, 
										"5", INTEGER);

	CPPUNIT_ASSERT(true == relClauseTable.existRelationshipEntry(PARENT, 
										"s", SYNONYM_ASSIGN, 
										"5", INTEGER));

	CPPUNIT_ASSERT(false == relClauseTable.existRelationshipEntry(PARENT, 
										"s", SYNONYM_ASSIGN, 
										"4", INTEGER));
}

void RelationshipClauseTableTest::testReplaceSynonym() {

	RelationshipClauseTable relClauseTable;

	relClauseTable.addRelationshipEntry(FOLLOWS, 
										"a", SYNONYM_ASSIGN, 
										"5", INTEGER);
	relClauseTable.addRelationshipEntry(FOLLOWS, 
										"s", SYNONYM_ASSIGN, 
										"5", INTEGER);


	relClauseTable.replaceSynonym("a", "d");
	CPPUNIT_ASSERT(2 == relClauseTable.getNumberOfEntries());

	relClauseTable.replaceSynonym("a", "s");
	CPPUNIT_ASSERT(1 == relClauseTable.getNumberOfEntries());

	RelationshipEntry relEntry;

	relEntry = relClauseTable.getRelationshipEntry(0);
	CPPUNIT_ASSERT(FOLLOWS == relEntry.relationshipType);
	CPPUNIT_ASSERT(2 == relEntry.numberOfArguments);
	CPPUNIT_ASSERT("a" == relEntry.relationshipArguments[0]);
	CPPUNIT_ASSERT(SYNONYM_ASSIGN == relEntry.relationshipArgumentTypes[0]);
	CPPUNIT_ASSERT("5" == relEntry.relationshipArguments[1]);
	CPPUNIT_ASSERT(INTEGER == relEntry.relationshipArgumentTypes[1]);

	relClauseTable = RelationshipClauseTable();
	relClauseTable.addRelationshipEntry(FOLLOWS, 
										"a", SYNONYM_ASSIGN, 
										"5", INTEGER);
	relClauseTable.addRelationshipEntry(FOLLOWS_STAR, 
										"a", SYNONYM_ASSIGN, 
										"s", SYNONYM_ASSIGN);
	relClauseTable.addRelationshipEntry(FOLLOWS, 
										"s", SYNONYM_ASSIGN, 
										"5", INTEGER);
	CPPUNIT_ASSERT(3 == relClauseTable.getNumberOfEntries());

	relClauseTable.replaceSynonym("a", "s");
	relEntry = relClauseTable.getRelationshipEntry(0);
	CPPUNIT_ASSERT(FOLLOWS == relEntry.relationshipType);
	CPPUNIT_ASSERT(2 == relEntry.numberOfArguments);
	CPPUNIT_ASSERT("a" == relEntry.relationshipArguments[0]);
	CPPUNIT_ASSERT(SYNONYM_ASSIGN == relEntry.relationshipArgumentTypes[0]);
	CPPUNIT_ASSERT("5" == relEntry.relationshipArguments[1]);
	CPPUNIT_ASSERT(INTEGER == relEntry.relationshipArgumentTypes[1]);

	relEntry = relClauseTable.getRelationshipEntry(1);
	CPPUNIT_ASSERT(FOLLOWS_STAR == relEntry.relationshipType);
	CPPUNIT_ASSERT(2 == relEntry.numberOfArguments);
	CPPUNIT_ASSERT("a" == relEntry.relationshipArguments[0]);
	CPPUNIT_ASSERT(SYNONYM_ASSIGN == relEntry.relationshipArgumentTypes[0]);
	CPPUNIT_ASSERT("a" == relEntry.relationshipArguments[1]);
	CPPUNIT_ASSERT(SYNONYM_ASSIGN == relEntry.relationshipArgumentTypes[1]);

	// if the argument is not a synonym, then it should not be replaced.
	relClauseTable = RelationshipClauseTable();
	relClauseTable.addRelationshipEntry(MODIFIES_LINE, 
										"a", SYNONYM_ASSIGN, 
										"argument", STRING);
	relClauseTable.replaceSynonym("a", "argument");
	relEntry = relClauseTable.getRelationshipEntry(0);
	CPPUNIT_ASSERT(MODIFIES_LINE == relEntry.relationshipType);
	CPPUNIT_ASSERT(2 == relEntry.numberOfArguments);
	CPPUNIT_ASSERT("a" == relEntry.relationshipArguments[0]);
	CPPUNIT_ASSERT(SYNONYM_ASSIGN == relEntry.relationshipArgumentTypes[0]);
	CPPUNIT_ASSERT("argument" == relEntry.relationshipArguments[1]);
	CPPUNIT_ASSERT(STRING == relEntry.relationshipArgumentTypes[1]);


}